package com.xpgk.mvc.base;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;
import com.xpgk.constant.ConstantRender;
import com.xpgk.mvc.codeSet.Code;
import com.xpgk.tools.ToolRandoms;
import com.xpgk.tools.ToolSqlXml;

import oracle.sql.TIMESTAMP;

/**
 * Model基础类
 * 
 * @param <M>
 * 
 *            抽取公共方法，并重写save、update、getDate方法
 */
public abstract class BaseModel<M extends Model<M>> extends Model<M> {

	private static final long serialVersionUID = -900378319414539856L;

	private static final Log log = Log.getLog(BaseModel.class);

	/**
	 * 字段描述：版本号 字段类型 ：bigint
	 */
	// public static final String column_version = "version";
	
	/**
	 * 字段描述：codeIds 字段类型 ：varchar 32
	 */
	public static final String column_codeIds = "codeIds";
	
	/**
	 * 通用查询获取类型
	 * @return
	 */
	public Code getCodes(){
		return Code.cacheGet(this.getStr(column_codeIds));
	}

	/**
	 * 获取SQL，固定SQL
	 * 
	 * @param sqlId
	 * @return
	 */
	protected static String getSqlMy(String sqlId) {
		return ToolSqlXml.getSqlMy(sqlId);
	}

	/**
	 * 获取SQL，动态SQL，使用Beetl解析
	 * 
	 * @param sqlId
	 * @param param
	 * @return
	 */
	protected static String getSqlByBeetl(String sqlId, Map<String, Object> param) {
		return ToolSqlXml.getSqlMy(sqlId, param, ConstantRender.sql_renderType_beetl);
	}

	/**
	 * 获取SQL，动态SQL，使用Beetl解析
	 * 
	 * @param sqlId
	 * @param param
	 *            查询参数
	 * @param list
	 *            用于接收预处理的值
	 * @return
	 */
	protected static String getSqlByBeetl(String sqlId, Map<String, Object> param, LinkedList<Object> list) {
		return ToolSqlXml.getSqlMy(sqlId, param, ConstantRender.sql_renderType_beetl, list);
	}

	/**
	 * 获取SQL，动态SQL，使用FreeMarker解析
	 * 
	 * @param sqlId
	 * @param param
	 * @return
	 */
	protected static String getSqlByFreeMarker(String sqlId, Map<String, Object> param) {
		return ToolSqlXml.getSqlMy(sqlId, param, ConstantRender.sql_renderType_freeMarker);
	}

	/**
	 * 获取SQL，动态SQL，使用FreeMarker解析
	 * 
	 * @param sqlId
	 * @param param
	 *            查询参数
	 * @param list
	 *            用于接收预处理的值
	 * @return
	 */
	protected static String getSqlByFreeMarker(String sqlId, Map<String, Object> param, LinkedList<Object> list) {
		return ToolSqlXml.getSqlMy(sqlId, param, ConstantRender.sql_renderType_freeMarker, list);
	}

	/**
	 * 获取SQL，动态SQL，使用Velocity解析
	 * 
	 * @param sqlId
	 * @param param
	 * @return
	 */
	protected static String getSqlByVelocity(String sqlId, Map<String, Object> param) {
		return ToolSqlXml.getSqlMy(sqlId, param, ConstantRender.sql_renderType_velocity);
	}

	/**
	 * 获取SQL，动态SQL，使用Velocity解析
	 * 
	 * @param sqlId
	 * @param param
	 *            查询参数
	 * @param list
	 *            用于接收预处理的值
	 * @return
	 */
	protected static String getSqlByVelocity(String sqlId, Map<String, Object> param, LinkedList<Object> list) {
		return ToolSqlXml.getSqlMy(sqlId, param, ConstantRender.sql_renderType_velocity, list);
	}

	/**
	 * 获取表映射对象
	 * 
	 * @return
	 */
	protected Table getTable() {
		return TableMapping.me().getTable(getClass());
	}

	/**
	 * 获取表名称
	 * 
	 * @return
	 */
	protected String getTableName() {
		return getTable().getName();
	}

	/**
	 * 获取主键名称
	 * 
	 * @return
	 */
	public String[] getPKNameArr() {
		return getTable().getPrimaryKey();
	}

	/**
	 * 获取主键名称
	 * 
	 * @return
	 */
	public String getPKNameStr() {
		String[] pkArr = getPKNameArr();
		if (pkArr.length == 1) {
			return pkArr[0];
		} else {
			String pk = "";
			for (String pkName : pkArr) {
				pk += pkName + ",";
			}
			return pk;
		}

	}

	/**
	 * 获取主键值：非复合主键
	 * 
	 * @return
	 */
	public String getPKValue() {
		String[] pkNameArr = getTable().getPrimaryKey();
		if (pkNameArr.length == 1) {
			return this.getStr(pkNameArr[0]);
		} else {
			String pk = "";
			for (String pkName : pkNameArr) {
				pk += this.get(pkName) + ",";
			}
			return pk;
		}
	}

	/**
	 * 获取主键值：复合主键
	 * 
	 * @return
	 */
	public List<Object> getPKValueList() {
		String[] pkNameArr = getTable().getPrimaryKey();

		List<Object> pkValueList = new ArrayList<Object>();
		for (String pkName : pkNameArr) {
			pkValueList.add(this.get(pkName));
		}

		return pkValueList;
	}

	/**
	 * 重写save方法，自动赋值，生成UUID值
	 */
	public boolean save() {
		String[] pkArr = getTable().getPrimaryKey();
		for (String pk : pkArr) {
			this.set(pk, ToolRandoms.getUuid(true)); // 设置主键值
		}
		return super.save();
	}

	/**
	 * 重写save方法，单主键，自定义主键值
	 */
	public boolean save(String pkIds) {
		String[] pkArr = getTable().getPrimaryKey();
		this.set(pkArr[0], pkIds); // 设置主键值
		return super.save();
	}

	/**
	 * 重写save方法，复合主键，自定义主键值
	 */
	public boolean save(Map<String, Object> pkMap) {
		Set<String> pkSet = pkMap.keySet();
		for (String pk : pkSet) {
			this.set(pk, pkMap.get(pk)); // 设置主键值
		}
		return super.save();
	}

	/**
	 * 重写update方法 如果存在版本号字段，则验证Model中的modifyFlag集合中是否包含version字段，
	 * 如果包含，则自动将版本号加1，并重新set版本号值
	 */
	@SuppressWarnings("unchecked")
	public boolean update() {

		Set<String> modifyFlag = null;
		try {
			Field field = this.getClass().getSuperclass().getSuperclass().getDeclaredField("modifyFlag");
			field.setAccessible(true);
			Object object = field.get(this);
			if (null != object) {
				modifyFlag = (Set<String>) object;
			}
			field.setAccessible(false);
		} catch (NoSuchFieldException e) {
			if (log.isErrorEnabled())
				log.error("业务Model类必须继承BaseModel");
			e.printStackTrace();
			throw new RuntimeException("业务Model类必须继承BaseModel");
		} catch (IllegalArgumentException e) {
			if (log.isErrorEnabled())
				log.error("BaseModel访问modifyFlag异常");
			e.printStackTrace();
			throw new RuntimeException("BaseModel访问modifyFlag异常");
		} catch (IllegalAccessException e) {
			if (log.isErrorEnabled())
				log.error("BaseModel访问modifyFlag异常");
			e.printStackTrace();
			throw new RuntimeException("BaseModel访问modifyFlag异常");
		}

		return super.update();
	}

	/**
	 * 针对Oracle做特殊处理
	 * 
	 * @param attr
	 * @return
	 */
	@Override
	public Date getDate(String attr) {
		Object obj = this.get(attr);
		if (null == obj) {
			return null;
		}

		if (TIMESTAMP.class.isAssignableFrom(obj.getClass())) {
			TIMESTAMP ts = (TIMESTAMP) obj;

			Date date = null;
			try {
				date = ts.timestampValue();
			} catch (SQLException e) {
				return null;
			}

			return date;
		}

		return (Date) obj;
	}

}
